from datetime import datetime

from marshmallow import ValidationError
from sqlalchemy.exc import SQLAlchemyError

from common.ApiResponse import ApiResponse
from common.BaseResponse import BaseResponse
from common.ErrorCode import ErrorCode
from constant.CommonConstant import SORT_ORDER_DESC, SORT_ORDER_ASC
from utils import ThreadLocal
from .validate import addScoringResult as addScoring, param_error, updateScoringResult, queryScoringResult
from flask import request
from models import db, ScoringResult, App
from my_decorator.AuthCheck import auth_check
from constant.UserConstant import *

# 数据验证模型
add_scoring_result = addScoring()
update_scoring_result = updateScoringResult()
query_scoring_result = queryScoringResult()


def addScoringResult():
    # 1.接收前端提交的数据-->json
    # 2.验证数据的合法性
    try:
        add_data = add_scoring_result.load(request.json)
    except ValidationError as err:
        print(f"添加校验出错：{err}")
        first_key, first_value = next(iter(err.messages.items()))
        return ApiResponse.error_from_baseResponse(
            baseResponse=param_error,
            data=first_value[0]
        )
    # 2.1 数据通过检验，解析数据
    user_map = ThreadLocal.ThreadLocalUtil.get()
    appId = add_data.get('appId')
    # 再次验证
    # 用户个人的app添加得分规则
    if user_map.get('user_role') == 'user':
        app = App.query.filter_by(id=appId, userId=user_map.get('id')).first()
        if app is None:
            print("你非管理员，同时这也并不是你的app,无权限")
            error_response = BaseResponse.from_error_code(error_code=ErrorCode.NO_AUTH_ERROR)
            return ApiResponse.error_from_baseResponse(
                baseResponse=error_response,
                data="你非管理员，同时这也并不是你的app,无权限"
            )
    try:
        resultName = add_data.get('resultName')
        resultDesc = add_data.get('resultDesc')
        resultPicture = add_data.get('resultPicture')
        resultProp = add_data.get('resultProp')
        if resultProp is not None:
            resultProp = ",".join(resultProp)
        resultScoreRange = add_data.get("resultScoreRange")
        # 2.2 创建“评分”对象
        score_result = ScoringResult(
            resultName=resultName,
            resultDesc=resultDesc,
            resultPicture=resultPicture,
            resultProp=resultProp,
            resultScoreRange=resultScoreRange,
            appId=appId,
            userId=user_map.get('id')
        )
        db.session.add(score_result)
        db.session.commit()
        return ApiResponse.success(data=f"成功创建{resultName}评分标准")
    except SQLAlchemyError as err:
        print(f"添加操作失败:{err}")
        error_response = BaseResponse.from_error_code(error_code=ErrorCode.OPERATION_ERROR)
        return ApiResponse.error_from_baseResponse(
            baseResponse=error_response,
            data="添加操作失败"
        )

@auth_check(required_roles=[ADMIN_ROLE, DEFAULT_ROLE])
def deleteScoringResult():
    # 1.接收前端提交的数据--> /scoring/delete?id=<id>
    try:
        res = validate_single_id(request.args.get('id'))
    except Exception as err:
        print(f"删除参数校验失败: {err}")
        error_response = BaseResponse.from_error_code(error_code=ErrorCode.PARAMS_ERROR)
        return ApiResponse.error_from_baseResponse(
            baseResponse=error_response,
            data="删除参数校验失败"
        )
    if not isinstance(res, int):
        print(f"删除id不是一个整数")
        error_response = BaseResponse.from_error_code(error_code=ErrorCode.PARAMS_ERROR)
        return ApiResponse.error_from_baseResponse(
            baseResponse=error_response,
            data="删除id不是一个整数"
        )
    # 2.在数据库层面验证数据的合法性
    scoring_result = validate_model_with_user(res)
    if not isinstance(scoring_result, ScoringResult):
        print(f"数据合法性返回结果类型出错")
        error_response = BaseResponse.from_error_code(error_code=ErrorCode.OPERATION_ERROR)
        return ApiResponse.error_from_baseResponse(
            baseResponse=error_response,
            data="数据合法性返回结果类型出错"
        )
    # 3.上述验证均通过，“逻辑删除”该评分标准
    scoring_result.isDelete = 1
    db.session.commit()
    return ApiResponse.success(data=f"已成功删除'{scoring_result.resultName}'评分标准")


@auth_check(required_roles=[ADMIN_ROLE, DEFAULT_ROLE])
def updateScoringResult():
    # 1.接收前端传递的数据 --> json
    # 2.进行简单的验证操作
    try:
        update_data = update_scoring_result.load(request.json)
    except ValidationError as err:
        print(f"更新参数校验失败:{err}")
        first_key, first_value = next(iter(err.messages.items()))
        return ApiResponse.error_from_baseResponse(
            baseResponse=param_error,
            data=first_value[0]
        )
    # 3.在数据库层面进行验证
    scoring_result = validate_model_with_user(update_data.get('id'))
    if not isinstance(scoring_result, ScoringResult):
        print(f"数据合法性返回结果类型出错")
        error_response = BaseResponse.from_error_code(error_code=ErrorCode.OPERATION_ERROR)
        return ApiResponse.error_from_baseResponse(
            baseResponse=error_response,
            data="数据合法性返回结果类型出错"
        )
    # 3.上述验证均通过，更新数据库
    try:
        update_fields = {
            "resultDesc": lambda v: {"resultDesc": v},
            "resultName": lambda v: {"resultName": v},
            "resultPicture": lambda v: {"resultPicture": v},
            "resultProp": lambda v: {"resultProp": ",".join(v)},
            "resultScoreRange": lambda v: {"resultScoreRange": v},
        }
        # 这个逼装的牛逼
        for field, func in update_fields.items():
            value = update_data.get(field)
            if value is not None:
                setattr(scoring_result, field, value)
        scoring_result.updateTime = datetime.now()
        db.session.commit()
        return ApiResponse.success(data=f"已成功更新'{scoring_result.resultName}'评分标准")
    except SQLAlchemyError as err:
        print(f"更新操作失败：{err}")
        error_response = BaseResponse.from_error_code(error_code=ErrorCode.OPERATION_ERROR)
        return ApiResponse.error_from_baseResponse(
            baseResponse=error_response,
            data="更新操作失败"
        )

def getScoringResult():
    # 1.接收前端传递的数据 -->/scoring/get?id=<id>
    try:
        res = validate_single_id(request.args.get('id'))
    except Exception as err:
        print(f"删除参数校验失败: {err}")
        error_response = BaseResponse.from_error_code(error_code=ErrorCode.PARAMS_ERROR)
        return ApiResponse.error_from_baseResponse(
            baseResponse=error_response,
            data="删除参数校验失败"
        )
    if not isinstance(res, int):
        print(f"删除id不是一个整数")
        error_response = BaseResponse.from_error_code(error_code=ErrorCode.PARAMS_ERROR)
        return ApiResponse.error_from_baseResponse(
            baseResponse=error_response,
            data="删除id不是一个整数"
        )
    # 2.在数据库层面验证数据
    scoring_result = validate_model_with_user(res)
    if not isinstance(scoring_result, ScoringResult):
        print(f"数据合法性返回结果类型出错")
        error_response = BaseResponse.from_error_code(error_code=ErrorCode.OPERATION_ERROR)
        return ApiResponse.error_from_baseResponse(
            baseResponse=error_response,
            data="数据合法性返回结果类型出错"
        )
    # 3.验证通过，向前端响应数据
    user_map = ThreadLocal.ThreadLocalUtil.get()
    if user_map.get('user_role') == 'user':
        return ApiResponse.success(
            data=scoring_result.Scoring_result_to_json_VO()
        )
    else:
        return ApiResponse.success(
            data=scoring_result.Scoring_result_to_json_admin()
        )


def listScoringResultByPage():
    # 1.接收前端提交的数据 --> json
    # 2.简单验证数据
    try:
        query_data = query_scoring_result.load(request.json)
    except ValidationError as err:
        print(f"分页查询参数出错：{err}")
        first_key, first_value = next(iter(err.messages.items()))
        return ApiResponse.error_from_baseResponse(
            baseResponse=param_error,
            data="分页查询参数出错"
        )
    # 3.验证通过，按条件查询数据
    # 数据库查询 + 分页
    user_map = ThreadLocal.ThreadLocalUtil.get()
    pagination = query_database(query_data=query_data, user_map=user_map)
    # 2.4 返回结果
    base_data = {
        "total": pagination.total,
        "pages": pagination.pages,
        "current": pagination.page,
        "pageSize": pagination.per_page
    }
    if user_map.get('user_role') == 'admin':
        base_data['scoring_results'] = [scoring_result.Scoring_result_to_json_admin() for scoring_result in pagination.items]
    else:
        base_data['scoring_results'] = [scoring_result.Scoring_result_to_json_VO() for scoring_result in pagination.items]
    print("base_data:", base_data)  # 添加调试输出
    return ApiResponse.success(data=base_data)

def recoverScoringResult():
    # 1.接收前端提交的数据--> /scoring/delete?id=<id>
    res = validate_single_id(request.args.get('id'))
    if not isinstance(res, int):
        return res
    # 2.在数据库层面验证数据的合法性
    scoring_result = validate_model_with_user(res,1)
    if isinstance(scoring_result, ApiResponse):
        return scoring_result
    # 3.上述验证均通过，“逻辑恢复”该评分标准
    scoring_result.isDelete = 0
    db.session.commit()
    return ApiResponse.success(data=f"已成功恢复'{scoring_result.resultName}'评分标准")


def validate_single_id(single_id):
    try:
        scoring_id = int(single_id)
    except ValueError as err:
        print("id输入的参数非法，应为整数!")
        return ApiResponse.error_from_baseResponse(
            baseResponse=param_error,
            data="id输入的参数非法，应为整数!"
        )
    except TypeError as err:
        print("id字段不可缺省！")
        return ApiResponse.error_from_baseResponse(
            baseResponse=param_error,
            data="id字段不可缺省！"
        )
    # id字段不可为负
    if scoring_id <= 0:
        print("id不可为负数,请重新检查要删除的评分标准！")
        return ApiResponse.error_from_baseResponse(
            baseResponse=param_error,
            data="id不可为负数,请重新检查要删除的评分标准！"
        )
    else:
        return scoring_id


# 这里默认的isDelete如果是管理员的列表的话应该是任意都可以
def validate_model_with_user(scoring_id: int,isDelete=0):
    user_map = ThreadLocal.ThreadLocalUtil.get()
    scoring_result = ScoringResult.query.filter(
        ScoringResult.id == scoring_id,
        ScoringResult.isDelete == isDelete
    )
    if user_map.get('user_role') == 'user':
        scoring_result = scoring_result.filter(
            ScoringResult.userId == user_map.get('id')
        )
    scoring_result = scoring_result.first()
    if scoring_result is None:
        print("评分标准不存在或者你无权处理")
        return ApiResponse.error_from_baseResponse(
            baseResponse=param_error,
            data="评分标准不存在或者你无权处理，请重新检查！"
        )
    else:
        return scoring_result


def query_database(query_data: query_scoring_result, user_map):
    #
    pageSize = query_data.get('pageSize')
    current = query_data.get('current')

    if user_map.get('user_role') == 'user':  # 防止爬虫
        if pageSize > 20:
            errorResponse = BaseResponse.from_error_code(ErrorCode.PARAMS_ERROR)
            return ApiResponse.error_from_baseResponse(errorResponse)
    # 2.1 创建基础查询对象
    query = ScoringResult.query
    # todo here 也许有点问题
    if user_map.get('user_role') == 'user':
        query = query.filter(ScoringResult.userId == user_map.get('id'))
    # 2.2 增添查询条件
    and_fields = {
        'resultName': lambda q, v: q.filter(ScoringResult.resultName.contains(v)),
        'resultDesc': lambda q, v: q.filter(ScoringResult.resultDesc.contains(v)),
        'isDelete': lambda q, v: q.filter(ScoringResult.isDelete == v),
        'appId': lambda q, v: q.filter(ScoringResult.appId == v),
        'userId': lambda q, v: q.filter(ScoringResult.userId == v),
        'resultProp': lambda q, v: q.filter(ScoringResult.resultProp.contains(v)),
        'resultScoreRange': lambda q, v: q.filter(ScoringResult.resultScoreRange == v)
    }
    # 2.2.1 动态构建’和‘查询
    for field, condition_func in and_fields.items():
        value = query_data.get(field)
        if value is not None:
            query = condition_func(query, value)
    # 2.2.2 动态排序字段
    sort_fields = {
        'id': ScoringResult.id,
        'resultName': ScoringResult.resultName,
        'resultDesc': ScoringResult.resultDesc,
        'resultProp': ScoringResult.resultProp,
        'resultScoreRange': ScoringResult.resultScoreRange,
        'appId': ScoringResult.appId,
        'userId': ScoringResult.userId,
        'createTime': ScoringResult.createTime,
        'updateTime': ScoringResult.updateTime
    }
    field_name = query_data.get("sortField")
    if field_name is not None:
        sortField = sort_fields.get(field_name)
        sortOrder = query_data.get('sortOrder')
        if sortOrder == SORT_ORDER_DESC:
            sortField = sortField.desc()
        elif sortOrder == SORT_ORDER_ASC:
            sortField = sortField.asc()
        else:
            print("排序字段有误，参数校验失败")
            errorResponse = BaseResponse.from_error_code(ErrorCode.PARAMS_ERROR)
            return ApiResponse.error_from_baseResponse(errorResponse, data="排序字段有误，参数校验失败")
        query = query.order_by(sortField)
    return query.paginate(page=current, per_page=pageSize)
